package com.itasura.guava.Cache;

import com.google.common.cache.*;
import com.itasura.guava.bean.City;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * 优点：
 * 提供了三种基本的缓存回收方式：基于容量回收、定时回收和基于引用回收。定时回收有两种：按照写入时间，最早写入的最先回收；按照访问时间，最早访问的最早回收
 * 缺点：
 * Guava Cache的超时机制不是精确的
 *
 * @author sailor wang
 * @date 2018/11/1 11:28 AM
 * @description
 */
@Slf4j
public class LoadingCacheTest {

    @Test
    public void loadingCacheTest() throws ExecutionException, InterruptedException {
        LoadingCache<String, City> loadingCache = CacheBuilder.newBuilder()
                //设置并发级别为8，并发级别是指可以同时写缓存的线程数
                .concurrencyLevel(8)
                //设置写缓存后8秒钟过期
                .expireAfterWrite(80, TimeUnit.SECONDS)
                //设置缓存容器的初始容量为10
                .initialCapacity(10)
                //设置缓存最大容量为100，超过100之后就会按照LRU最近虽少使用算法来移除缓存项
                .maximumSize(100)
                //设置要统计缓存的命中率
                .recordStats()
                //设置缓存的移除通知
                .removalListener(new RemovalListener<Object, Object>() {
                    @Override
                    public void onRemoval(RemovalNotification<Object, Object> removalNotification) {
                        String key = (String) removalNotification.getKey();
                        City val = (City) removalNotification.getValue();
                        RemovalCause cause = removalNotification.getCause();
                        log.info("缓存移除通知 key -> {}, val -> {}, cause -> {}", key, val, cause);
                    }
                })
                .build(new CacheLoader<String, City>() {
                    @Override
                    public City load(String cityCode) throws Exception {
                        City city = new City();
                        city.setZipCode(cityCode);
                        log.info("loading cache -> {}", city);
                        return city;
                    }
                });

        for (int i = 1; i <= 10; i++) {
            City city = loadingCache.get(String.valueOf(i));
            log.info("get city from cache -> {}", city);
            TimeUnit.MILLISECONDS.sleep(500);
        }

        log.info("缓存首次命中率 -> {}", loadingCache.stats());

        for (int i = 1; i <= 10; i++) {
            City city = loadingCache.get(String.valueOf(i));
            log.info("get city from cache -> {}", city);
            TimeUnit.MILLISECONDS.sleep(500);
        }

        log.info("缓存后续命中率 -> {}", loadingCache.stats());
    }
}